import 'ol/ol.css';

import Icon from 'ol/style/Icon';
import Style from 'ol/style/Style';
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import TileLayer from 'ol/layer/Tile.js';
import XYZ from 'ol/source/XYZ';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import { Point } from 'ol/geom';
import Feature from 'ol/Feature';
import { now, FrameLoopMachine } from '../../utils/FrameLoopMachine.js'

// 研究这两种策略的大环境背景
// 使用websocket进行position同步, websocket每隔一个模糊时间(500ms~1000ms)发送一次位置同步的指令, 不使用插值动画时, 物体位移过于生硬
// 1. 物体运动变得稍微平滑
// 2. 能大致反应物体的运动速率

// 策略2
// 对上上次同步与上次同步的位置进行插值
// 插值使用值为上次获取指令时间戳与这次获取指令时间戳的插值
// 需要弥补停止运动前最后一帧的定义

// 对比策略:
// 1. 能精确反应出物体的运动速率
// 2. 编码较为复杂

/** 初始化websocket功能 */
const initWebSocket = () => {
    if (!"WebSocket" in window) { return; }
    const socket = new WebSocket("ws://localhost:5173/wstest");
    socket.addEventListener('error', (error) => { });
    socket.addEventListener('close', (event) => { });
    socket.addEventListener('open', () => { });
    window.addEventListener('beforeunload', (event) => { socket.close(); });
    return socket;
}

/** 初始化openlayers地图 */
const initOpenlayers = (id) => {
    const map = new Map({ target: id });
    const view = new View({ projection: "EPSG:3857", center: [0, 0], zoom: 10, });
    map.setView(view);
    return { map, view };
}

// 模拟匀速运动
const speed = 2000;
const randomStepCoordY = (deltaFactor) => (0.5 + 0.5 * Math.random() * deltaFactor) * speed;

export const initialize = (id) => {

    const { map, view } = initOpenlayers(id);

    // 1. 矢量图层, 矢量源, 点几何, Feature
    const vectorSource = new VectorSource();
    const vectorLayer = new VectorLayer({ source: vectorSource });
    const pointGeometry = new Point([0.0, 0.0]);
    const feature = new Feature({ geometry: pointGeometry });
    const iconStyle = new Style({ image: new Icon({ src: "/aht.png", anchor: [0.5, 0.5] }) });
    feature.setStyle(iconStyle);
    vectorSource.addFeature(feature);
    map.addLayer(vectorLayer);

    // 2. 利用Feature存储动画插帧需要的参数
    feature.currentLerp = 0.0;
    feature.needsUpdate = false;
    const x = feature.getGeometry().flatCoordinates[0]; // x坐标
    const y = feature.getGeometry().flatCoordinates[1]; // y坐标
    feature.lastlast = 0.0; // 上次收到指令
    feature.last = 1.0; // 这一次收到指令
    feature.lastlastlastP = [x, y]; // 上上个位置
    feature.lastlastP = [x, y]; // 上个位置
    feature.lastP = [x, y]; // 这一次的位置


    // 网络部分
    let websocketID = undefined; // 当前客户端记录的id
    const socket = initWebSocket();
    socket.addEventListener('message', (event) => {
        const message = JSON.parse(event.data);

        // 收到连接指令时记录一下服务器给客户端生成的id号
        if (message['type'] === 'connection') { websocketID = message['data']; }

        // 每次接收到移动的指令
        else if (message['type'] === 'move') {
            if (!pointGeometry.flatCoordinates.length) { return; } // 保证点已经被加载到数据源

            // 记录一下获取指令的时间戳
            feature.lastlast = feature.last;
            feature.last = now();
            const deltaFactor = ((feature.last - feature.lastlast) - 0.5) / 0.5;

            // 在当前帧获取的位置基础上, 随机Y轴步长生成一个下一帧位置
            const x = feature.lastP[0];
            const y = feature.lastP[1] + randomStepCoordY(deltaFactor);

            // 上上个位置
            feature.lastlastlastP[0] = feature.lastlastP[0];
            feature.lastlastlastP[1] = feature.lastlastP[1];

            // 上个位置
            feature.lastlastP[0] = feature.lastP[0];
            feature.lastlastP[1] = feature.lastP[1];

            // 当前位置
            feature.lastP[0] = x;
            feature.lastP[1] = y;

            feature.needsUpdate = true;
            feature.currentLerp = 0.0;
        }
    });

    // 使用帧循环以进行补帧
    const flm = FrameLoopMachine((elapsedTime, deltaTime) => {

        // 这一次请求的时间戳-上一次请求的时间戳
        // 在这个时间范围内, 对上上次请求的位置与上一次请求的位置进行插帧
        const targetLerpTime = feature.last - feature.lastlast;
        const percent = deltaTime / targetLerpTime; // 插值百分比

        if (feature.currentLerp >= 1.0) { feature.needsUpdate = false; }
        if (feature.needsUpdate) {
            if (feature.currentLerp + percent >= 1.0) { feature.currentLerp = 1.0; }
            else { feature.currentLerp += percent; }

            const x = feature.lastlastlastP[0] * (1.0 - feature.currentLerp) + feature.lastlastP[0] * feature.currentLerp;
            const y = feature.lastlastlastP[1] * (1.0 - feature.currentLerp) + feature.lastlastP[1] * feature.currentLerp;
            pointGeometry.setCoordinates([x, y]);
        }
    });
    flm.startLoop();
};